//
// Created by 史振江 on 7/13/23.
//
#ifndef SPLAY_SAFE_QUEUE_H
#define SPLAY_SAFE_QUEUE_H

#include <queue>
#include <pthread.h>
#include "defind-util.h"

using namespace std;

template<typename T>
class SafeQueue {
private:
    // 定义函数指针
    typedef void (*ReleaseCallBack)(T *);

    // 同步
    typedef void (*SyncCallBack)(queue<T> &);

private:
    queue<T> queue;
    pthread_mutex_t mutex; // 互斥锁
    pthread_cond_t cond; // wait or notify
    int work; // 标记队列是否工作 0工作; 1睡觉;
    bool isWait = false; // true等待，
    ReleaseCallBack callBack; // 释放回调
    SyncCallBack syncCallback; // 音视频同步回调

public:
    SafeQueue() {
        // 初始化互斥锁
        pthread_mutex_init(&mutex, 0);
        pthread_cond_init(&cond, 0);
    };

    ~SafeQueue() {
        // 释放资源
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
    };

    void setWait(bool flag) {
        pthread_mutex_lock(&mutex); // 锁
        LOG_D("isWait:%d\tflag:%d",isWait,flag)
        isWait = flag;
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex); // 释放锁
    }

    void setReleaseCallBack(ReleaseCallBack releaseCallBack) {
        this->callBack = releaseCallBack;
    }

    void insert(T t) {
        pthread_mutex_lock(&mutex); // 锁
        if (work) { // 工作状态
            queue.push(t);
            pthread_cond_signal(&cond); // 唤醒睡觉的人
        } else {
            // 非工作状态
            if (callBack != nullptr) {
                callBack(&t); // 回调，释放工作 [因为是T类型，无法手动释放，所以回调释放]
            }
        }
        pthread_mutex_unlock(&mutex); // 释放锁
    }

    // 出队列
    // return : true; 出队列成功
    bool get(T &value) { // 传递引用类型
        bool flag = false;
        pthread_mutex_lock(&mutex); // 锁

        // isWait 是否等待
        if (isWait) {
            pthread_cond_wait(&cond, &mutex); // 等待
        }

        // 工作状态，并且队列中为empty
        while (work && queue.empty()) {
//            LOG_D("szj等待")
            // 如果现在是工作状态，并且队列中是空的
            pthread_cond_wait(&cond, &mutex); // 等待
        }

        if (!queue.empty()) {
            value = queue.front();// 取出第一个值，并赋值给外界
            queue.pop(); // 出队列
            flag = true; // 标识取出成功
        }

        pthread_mutex_unlock(&mutex); // 释放锁
        return flag;
    }

    void setWork(int wk) {
        pthread_mutex_lock(&mutex); // 锁
        this->work = wk; // 设置工作状态
        pthread_cond_signal(&cond); // 唤醒睡觉的人
        pthread_mutex_unlock(&mutex); // 锁
    }

    int size() const {
        return queue.size();
    }

    int is_empty() const {
        return queue.empty();
    }

    void clear() {
        pthread_mutex_lock(&mutex); // 锁

        for (int i = 0; i < size(); ++i) {
            T value = queue.front();
            if (callBack) {
                callBack(&value); // 外界释放
            }
            queue.pop();// 出队列
        }

        pthread_mutex_unlock(&mutex); // 解锁
    }

    void setSyncCallBack(SyncCallBack s) {
        this->syncCallback = s;
    }

    void sync() {
        pthread_mutex_lock(&mutex);

        syncCallback(this->queue); // 函数指针 具体丢包动作，让外界完成
        pthread_mutex_unlock(&mutex);
    }
};


#endif //SPLAY_SAFE_QUEUE_H
